#region Using Statements
using System;
using System.Collections.Generic;
using System.Xml;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion

namespace SkyBurner
{
    public enum StarFighterStatus
    {
        Alive,
        Falling,
        Exploding,
        Dead, 
        Escape,
        LevelComplete
    }

    public partial class StarFighter : SkyBurnerWorldObject
    {
        #region Private members
        private StarFighterStatus m_Status;    
        private MOODModel m_tcStarFighterModel;
        private MOODModel m_tcStarFighterShieldModel;
        private Vector3 m_vMoveConstrain;
        private Vector3 m_vMoveSpeed;
        private float m_fRollSpeed;

        private Vector3 m_vStarFighterCenterPosition;
        private Vector3 m_vLaserColor = new Vector3(1.0f, 1.0f, 0.0f);
        private Vector3 m_vSunLightPosition;

        private float m_fRoll;
        private float m_fDeathRoll;
        private float m_elapsedTime;
        private float m_escapeElapsedTime;

        private MOODBlinnPhongShader m_moodBlinnPhongShader;
        private MOODShieldGlassShader m_moodShieldGlassShader;
        private Texture2D m_normalFireTexture;
        private Texture2D m_rainbowTexture;

        private float m_fFireLifeTime;
        private float m_fFireSpeed;
        private float m_fFireSize;
        private float m_fFireDamage;
        private float m_fFireRadius;
        private float m_fRocketLifeTime;
        private float m_fRocketSpeed;
        private float m_fRocketDamage;
        private float m_fRocketRadius;
        private float m_fLastFireTime;
        private float m_fLastFireRocketTime;
        private bool m_bUseShield;
        private float m_fShieldPower;

        private ParticleEmitterRocketSmoke m_destroySmokeEmitter;
        private ParticleEmitterBase m_explosionEmitter;
        #endregion

        #region Properties
        public BoundingBoxEx BoundingBox
        {
            get { return m_tcStarFighterModel.BoundingBox; }
        }

        public float Roll
        {
            get { return m_fRoll; }
        }

        public StarFighterStatus Status
        {
            get { return m_Status; }
            set { m_Status = value; }
        }
        #endregion

        public StarFighter(BaseGame game, SkyBurnerWorld pSkyBurnerWorld, Vector3 vStartPosition, XmlNode pConfigNode)
            : base(game, pSkyBurnerWorld)
        {
            String playerShipModel;
            XMLPropertyBag xmlPropertyBag = new XMLPropertyBag(pConfigNode);

            m_fRoll = 0.0f;
            m_fLastFireTime = 0.0f;
            m_fLastFireRocketTime = 0.0f;
            m_bUseShield = false;
            m_fShieldPower = 1.0f;
            m_fDeathRoll = 0.0f;

            // load configuration...
            playerShipModel = xmlPropertyBag.GetValue<String>("Model", XMLPropertyBagValueType.vtString);
            m_vMoveSpeed = xmlPropertyBag.GetValue<Vector3>("MoveSpeed", XMLPropertyBagValueType.vtVector3);
            m_fRollSpeed = xmlPropertyBag.GetValue<float>("RollSpeed", XMLPropertyBagValueType.vtFloat);
            m_vMoveConstrain = xmlPropertyBag.GetValue<Vector3>("MoveConstrain", XMLPropertyBagValueType.vtVector3);
            m_fFireLifeTime = xmlPropertyBag.GetValue<float>("FireLifeTime", XMLPropertyBagValueType.vtFloat);
            m_fFireSpeed = xmlPropertyBag.GetValue<float>("FireSpeed", XMLPropertyBagValueType.vtFloat);
            m_fFireSize = xmlPropertyBag.GetValue<float>("FireSize", XMLPropertyBagValueType.vtFloat);
            m_fFireDamage = xmlPropertyBag.GetValue<float>("FireDamage", XMLPropertyBagValueType.vtFloat);
            m_fFireRadius = xmlPropertyBag.GetValue<float>("FireRadius", XMLPropertyBagValueType.vtFloat);
            m_fRocketLifeTime = xmlPropertyBag.GetValue<float>("RocketLifeTime", XMLPropertyBagValueType.vtFloat);
            m_fRocketSpeed = xmlPropertyBag.GetValue<float>("RocketSpeed", XMLPropertyBagValueType.vtFloat);
            m_fRocketDamage = xmlPropertyBag.GetValue<float>("RocketDamage", XMLPropertyBagValueType.vtFloat);
            m_fRocketRadius = xmlPropertyBag.GetValue<float>("RocketRadius", XMLPropertyBagValueType.vtFloat);

            // initialize toys...
            m_tcStarFighterModel = new MOODModel(game, playerShipModel);
            m_tcStarFighterShieldModel = new MOODModel(game, "Data\\Models\\starfightershield.mood");

            m_moodBlinnPhongShader = (MOODBlinnPhongShader)m_Game.ShadersManager.GetShader("BlinnPhongShader");
            m_moodShieldGlassShader = (MOODShieldGlassShader)m_Game.ShadersManager.GetShader("ShieldGlassShader");

            m_normalFireTexture = m_Game.ContentManager.Load<Texture2D>("Data\\Textures\\bullet_sprite_02");
            m_rainbowTexture = m_Game.ContentManager.Load<Texture2D>("Data\\Textures\\rainbow");

            m_vPosition = vStartPosition;
            m_vStarFighterCenterPosition = vStartPosition;
            m_elapsedTime = 0.0f;
            m_escapeElapsedTime = 0.0f;

            // get sunlight position...
            BaseWorldLight sunLight = pSkyBurnerWorld.GetLight("SunLight");
            if (sunLight != null)
                m_vSunLightPosition = sunLight.Position;

            m_Status = StarFighterStatus.Alive;
        }

        protected void OnUpdateInAliveStatus(GameTime gameTime, Camera pActiveCamera)
        {
            m_elapsedTime += gameTime.ElapsedGameTime.Milliseconds;
            if (m_elapsedTime < 1000.0f)
            {
                m_vPosition.Y += -0.25f * m_vMoveSpeed.Y * gameTime.ElapsedGameTime.Milliseconds;
                m_vPosition.Z += m_vMoveSpeed.Z * gameTime.ElapsedGameTime.Milliseconds;
            }
            else
            {
                m_vPosition.X -= m_Game.UserInputState.DeltaX * m_vMoveSpeed.X * gameTime.ElapsedGameTime.Milliseconds;
                m_vPosition.Y += m_Game.UserInputState.DeltaY * m_vMoveSpeed.Y * gameTime.ElapsedGameTime.Milliseconds;
                m_vPosition.Z += m_vMoveSpeed.Z * gameTime.ElapsedGameTime.Milliseconds;
            }

            if (Math.Abs(m_vPosition.X - m_vStarFighterCenterPosition.X) >= m_vMoveConstrain.X)
            {
                if (m_vPosition.X > 0.0f)
                    m_vPosition.X = m_vMoveConstrain.X;
                else
                    m_vPosition.X = -m_vMoveConstrain.X;

                if (m_fRoll < 0)
                    m_fRoll += m_fRollSpeed * gameTime.ElapsedGameTime.Milliseconds;
                else if (m_fRoll > 0)
                    m_fRoll -= m_fRollSpeed * gameTime.ElapsedGameTime.Milliseconds;
            }
            else
            {
                if (m_Game.UserInputState.DeltaX > 0)
                {
                    if (m_fRoll < 0.2f)
                        m_fRoll += m_fRollSpeed * gameTime.ElapsedGameTime.Milliseconds;
                }
                else if (m_Game.UserInputState.DeltaX < 0)
                {
                    if (m_fRoll > -0.2f)
                        m_fRoll -= m_fRollSpeed * gameTime.ElapsedGameTime.Milliseconds;
                }
                else
                {
                    if (m_fRoll < 0)
                        m_fRoll += m_fRollSpeed * gameTime.ElapsedGameTime.Milliseconds;
                    else if (m_fRoll > 0)
                        m_fRoll -= m_fRollSpeed * gameTime.ElapsedGameTime.Milliseconds;
                }
            }

            if (Math.Abs(m_vPosition.Y - m_vStarFighterCenterPosition.Y) >= m_vMoveConstrain.Y)
            {
                if ((m_vPosition.Y - m_vStarFighterCenterPosition.Y) > 0)
                    m_vPosition.Y = m_vStarFighterCenterPosition.Y + m_vMoveConstrain.Y;
                else
                    m_vPosition.Y = m_vStarFighterCenterPosition.Y - m_vMoveConstrain.Y;
            }

            if (m_bUseShield)
            {
                m_fShieldPower -= (0.0005f * (float)gameTime.ElapsedGameTime.Milliseconds);
                if (m_fShieldPower <= 0.0f)
                {
                    m_bUseShield = false;
                    m_fShieldPower = 1.0f;
                }
            }

            // check for user input
            if (m_Game.UserInputState.IsUserAction(UserAction.ButtonA))
                OnFire(gameTime);

            if (m_Game.UserInputState.IsUserAction(UserAction.RightTrigger) && (SkyBurnerGlobal.RocketCount > 0))
                OnFireRocket(gameTime);

            if (!m_bUseShield && m_Game.UserInputState.IsUserAction(UserAction.LeftTrigger))
                OnUseShield();

            // change status if there is no more energy...
            if (SkyBurnerGlobal.EnergyValue <= 0)
                m_Status = StarFighterStatus.Falling;
        }

        protected void OnUpdateInFallingStatus(GameTime gameTime, Camera pActiveCamera)
        {
            if (m_destroySmokeEmitter == null)
            {
                m_destroySmokeEmitter = (ParticleEmitterRocketSmoke)m_skyBurnerWorld.ParticleSystemManager.CreateEmitter("StarFighterSmoke");
                m_Status = StarFighterStatus.Falling;
            }                      
            if (m_vMoveSpeed.Z > 0.0f)
                m_vMoveSpeed.Z -= 0.0001f;
            else
                m_vMoveSpeed.Z = 0.0f;

            if (m_vPosition.Y >= 0.0f)
                m_vPosition.Y -= 0.25f * m_vMoveSpeed.Y * gameTime.ElapsedGameTime.Milliseconds;
            else
                m_vPosition.Y = 0.0f;

            m_fDeathRoll += 0.25f;

            m_vPosition.Z += m_vMoveSpeed.Z * gameTime.ElapsedGameTime.Milliseconds;
            m_destroySmokeEmitter.Position = m_vPosition;

            // change status if smoke emitter ends...
            if (m_destroySmokeEmitter.Dead)
                m_Status = StarFighterStatus.Exploding;
        }

        protected void OnUpdateInExplodingStatus(GameTime gameTime, Camera pActiveCamera)
        {
            if (m_explosionEmitter == null)
            {
                m_explosionEmitter = m_skyBurnerWorld.ParticleSystemManager.CreateEmitter("Explosion");
                m_explosionEmitter.Position = m_vPosition;
            }

            if (m_explosionEmitter.Dead)
                m_Status = StarFighterStatus.Dead;
        }

        protected void OnUpdateInEscapeStatus(GameTime gameTime, Camera pActiveCamera)
        {
            m_escapeElapsedTime += gameTime.ElapsedGameTime.Milliseconds;
            if (m_escapeElapsedTime < 3000.0f)
            {
                m_vPosition.Y += 0.25f * m_vMoveSpeed.Y * gameTime.ElapsedGameTime.Milliseconds;
                m_vPosition.Z += m_vMoveSpeed.Z * gameTime.ElapsedGameTime.Milliseconds;
            }
            else
                m_Status = StarFighterStatus.LevelComplete;
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime, Camera pActiveCamera)
        {
            switch (m_Status)
            {
                case StarFighterStatus.Alive:
                    {
                        OnUpdateInAliveStatus(gameTime, pActiveCamera);
                        break;
                    }

                case StarFighterStatus.Falling:
                    {
                        OnUpdateInFallingStatus(gameTime, pActiveCamera);
                        break;
                    }

                case StarFighterStatus.Exploding:
                    {
                        OnUpdateInExplodingStatus(gameTime, pActiveCamera);
                        break;
                    }

                case StarFighterStatus.Dead:
                    {
                        break;
                    }

                case StarFighterStatus.Escape:
                    {
                        OnUpdateInEscapeStatus(gameTime, pActiveCamera);
                        break;
                    }

                case StarFighterStatus.LevelComplete:
                    {
                        break;
                    }
            }
            base.Update(gameTime, pActiveCamera);
        }

        public override void Draw(GameTime gameTime, Camera pActiveCamera)
        {
            base.Draw(gameTime, pActiveCamera);

            if ((m_Status == StarFighterStatus.Alive) || (m_Status == StarFighterStatus.Falling) || (m_Status == StarFighterStatus.Escape))
            {
                m_tcStarFighterModel.Update(gameTime, pActiveCamera);

                m_tcStarFighterModel.WorldMatrix = Matrix.CreateRotationZ(m_fRoll) * Matrix.CreateRotationZ(m_fDeathRoll) * Matrix.CreateTranslation(m_vPosition);
                m_tcStarFighterModel.ViewMatrix = Matrix.CreateLookAt(pActiveCamera.Position, pActiveCamera.LookAt, pActiveCamera.Up);
                m_tcStarFighterModel.ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(pActiveCamera.FOV, pActiveCamera.AspectRatio, pActiveCamera.NearPlane, pActiveCamera.FarPlane);

                m_moodBlinnPhongShader.Draw(gameTime, pActiveCamera, pActiveCamera.Position, m_vPosition + m_vSunLightPosition, m_tcStarFighterModel);

                if (m_bUseShield)
                {
                    m_tcStarFighterShieldModel.WorldMatrix = m_tcStarFighterModel.WorldMatrix;
                    m_tcStarFighterShieldModel.ViewMatrix = m_tcStarFighterModel.ViewMatrix;
                    m_tcStarFighterShieldModel.ProjectionMatrix = m_tcStarFighterModel.ProjectionMatrix;

                    m_moodShieldGlassShader.Draw(gameTime, pActiveCamera, pActiveCamera.Position, m_fShieldPower, m_skyBurnerWorld.SkyCube.Texture, m_rainbowTexture, m_tcStarFighterShieldModel);
                }
            }
        }

        protected void OnUseShield()
        {
            if (!m_bUseShield && (SkyBurnerGlobal.ShieldValue > 0))
            {
                m_bUseShield = true;
                SkyBurnerGlobal.DecrementShield(25);
            }
        }

        protected void OnFire(GameTime gameTime)
        {
            if ((gameTime.TotalGameTime.TotalMilliseconds - m_fLastFireTime) > 200.0f)
            {
                Vector3 vFirePosition = m_vPosition;
                Vector3 vFireDirection = Vector3.UnitZ;


                m_skyBurnerWorld.AddBullet(new SkyBurnerBulletSprite(m_Game, 
                                                                      m_skyBurnerWorld, 
                                                                      m_normalFireTexture, 
                                                                      new Vector3(vFirePosition.X - 0.4f, vFirePosition.Y, vFirePosition.Z), 
                                                                      vFireDirection, 
                                                                      m_fFireSpeed, 
                                                                      m_fFireLifeTime, 
                                                                      m_fFireDamage, 
                                                                      m_fFireRadius, 
                                                                      m_vLaserColor), 
                                            SkyBurnerWorld.BulletFrom.Enemy);

                m_skyBurnerWorld.AddBullet(new SkyBurnerBulletSprite(m_Game,
                                                                      m_skyBurnerWorld,
                                                                      m_normalFireTexture,
                                                                      new Vector3(vFirePosition.X + 0.4f, vFirePosition.Y, vFirePosition.Z),
                                                                      vFireDirection,
                                                                      m_fFireSpeed,
                                                                      m_fFireLifeTime,
                                                                      m_fFireDamage,
                                                                      m_fFireRadius,
                                                                      m_vLaserColor),
                                            SkyBurnerWorld.BulletFrom.Enemy);
                    
                m_Game.SoundManager.PlaySound("PlasmaShoot");
                m_fLastFireTime = (float)gameTime.TotalGameTime.TotalMilliseconds;
            }
        }

        protected void OnFireRocket(GameTime gameTime)
        {
            if ((gameTime.TotalGameTime.TotalMilliseconds - m_fLastFireRocketTime) > 500.0f)
            {
                Vector3 vFirePosition = m_vPosition + (Vector3.UnitZ * 2.0f);
                Vector3 vFireDirection = Vector3.UnitZ;

                ParticleEmitterRocketSmoke rocketSmokeEmitter = (ParticleEmitterRocketSmoke)m_skyBurnerWorld.ParticleSystemManager.CreateEmitter("RocketSmoke");
                m_skyBurnerWorld.AddBullet(new SkyBurnerRocketBullet(m_Game, 
                                                                     m_skyBurnerWorld, 
                                                                     m_vSunLightPosition,
                                                                     Matrix.Identity,
                                                                     vFirePosition, 
                                                                     vFireDirection, 
                                                                     m_fRocketSpeed,
                                                                     m_fRocketLifeTime,
                                                                     m_fRocketDamage,
                                                                     m_fRocketRadius,
                                                                     rocketSmokeEmitter), 
                                           SkyBurnerWorld.BulletFrom.Player);

                m_Game.SoundManager.PlaySound("RocketShoot");
                
                SkyBurnerGlobal.DecrementRocket();

                m_fLastFireRocketTime = (float)gameTime.TotalGameTime.TotalMilliseconds;
            }
        }

        public void HandleCollision(SkyBurnerBulletBase pBullet)
        {
            if (!m_bUseShield)
            {
                SkyBurnerGlobal.DecrementEnergy((int)pBullet.Damage);
                m_Game.UserInputState.Rumble(1.0f);
                m_Game.PostScreenEffectsManager.AddPostScreenEffect(new PostScreenEffectDistorted(m_Game, 500.0f, 0.5f));
            }
        }

        public void HandleCollisionWithEnemy(AI.EnemyUnitBase pEnemyUnitBase)
        {
            if (!m_bUseShield)
            {
                SkyBurnerGlobal.DecrementEnergy(pEnemyUnitBase.Damage);
                m_Game.UserInputState.Rumble(1.0f);
                m_Game.PostScreenEffectsManager.AddPostScreenEffect(new PostScreenEffectDistorted(m_Game, 500.0f, 0.5f));
            }            
        }
    }
}
